#!/bin/ksh
#
# CDDL HEADER START
#
# The contents of this file are subject to the terms of the
# Common Development and Distribution License (the "License").
# You may not use this file except in compliance with the License.
#
# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
# or http://www.opensolaris.org/os/licensing.
# See the License for the specific language governing permissions
# and limitations under the License.
#
# When distributing Covered Code, include this CDDL HEADER in each
# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
# If applicable, add the following below this CDDL HEADER, with the
# fields enclosed by brackets "[]" replaced with your own identifying
# information: Portions Copyright [yyyy] [name of copyright owner]
#
# CDDL HEADER END
#
#
# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
# Use is subject to license terms.
#
#

PATH=/bin:/usr/bin:/usr/sbin export PATH

TEXTDOMAIN="SUNW_OST_OSCMD"
export TEXTDOMAIN

PFEXEC=/usr/bin/pfexec
LPSET=/usr/bin/lpset
LPGET=/usr/bin/lpget
LPSTAT=/usr/bin/lpstat
LPADMIN=/usr/lib/lp/local/lpadmin
LPFILTER=/usr/sbin/lpfilter
COMM=/usr/bin/comm
PPDMGR=/usr/sbin/ppdmgr
MKTEMP="/usr/bin/mktemp -t"

HOST=$(/bin/uname -n)
exit_code=0

usage() {
	gettext "Usage:\n" 1>&2
	gettext "	lpadmin -p (printer) (options)\n" 1>&2
	gettext "	lpadmin -x (dest)\n" 1>&2
	gettext "	lpadmin -d (dest)\n" 1>&2
	gettext "	lpadmin -S print-wheel -A alert-type [ -W minutes ]\n" 1>&2
	gettext "		[ -Q requests ]\n" 1>&2
	gettext "	lpadmin -M -f form-name [ -a [ -o filebreak ]\n" 1>&2
	gettext "		[ -t tray-number ]]\n" 1>&2
	exit 1
}

# create a filter table for LP service
lp_config_filters() {
	if [[ ! -f /etc/lp/filter.table ]] ; then
		cd /etc/lp/fd ; for filter in *.fd ; do
			${PFEXEC} ${LPFILTER} \
				-f $(/usr/bin/basename $filter .fd) \
				-F $filter
		done
	fi
}

# enable/disable LP related service(s)
lp_config_service() {	# (enable | disable)
	svcadm ${1} -s svc:/application/print/server:default
	# svcadm ${1} -s svc:/application/print/rfc1179:default
}

# synchronize printers.conf with LP configuration changes
lp_config_sync_pconf() {	# (pre) (post)
	ADDED=$(${COMM} -13 ${1} ${2})
	REMOVED=$(${COMM} -23 ${1} ${2})

	lp_server=${server:-${HOST}}
	for DEST in ${ADDED} ; do
		lp_uri="ipp://${lp_server}/printers/${DEST}"
		lp_bsdaddr="${lp_server},${DEST},Solaris"
		${LPSET} -n system \
			-a "printer-uri-supported=${lp_uri}" \
			-a "bsdaddr=${lp_bsdaddr}" \
		 	${DEST} 2>/dev/null
	done

	for DEST in ${REMOVED} ; do
		${LPSET} -n system -x ${DEST} 2>/dev/null
	done
}

# Delete all destinations in printers.conf
delete_all() {
	for DEST in $(lpget -n system list | egrep -e '.+:$' | sed -e 's/://')
	do
		${LPSET} -n system -x ${DEST}
		status=$?
	done
}

# Call the ppdmgr utility to add a new PPD file to the system.
#
# $1  - path to PPD file
# $2  - label name (optional)
add_new_ppd_file() {
	# Add new ppd file and echo full path it was actually saved to
	ppdmgrcmd="${PFEXEC} ${PPDMGR} -a ${1} -w"

	ppderrfile=$(${MKTEMP} lpadminerror.XXXXXX)
	if [[ -z "${ppderrfile}" ]] ; then
		gettext "lpadmin: System error; cannot create temporary file\n" 1>&2
		exit 2
	fi
	ppd_file=$(${ppdmgrcmd} 2>${ppderrfile})
	ppdmgrrc=$?
	if [[ -s "${ppderrfile}" ]] ; then
		print -n "lpadmin: " 1>&2
		cat ${ppderrfile} 1>&2
		rm -f ${ppderrfile} >/dev/null 2>&1
		if [[ ${ppdmgrrc} -ne 0 ]] ; then
			exit 1
		fi
	fi
	rm -f ${ppderrfile} >/dev/null 2>&1
}

#
# Execution begins here
#

# be sure that we can run lpset and lpget
if [[ ! -x ${LPSET} || ! -x ${LPGET} ]] ; then
	gettext "lpadmin: System error; cannot set default printer\n" 1>&2
	exit 2
fi

if [[ $# -lt 1 ]] ; then
	usage
	exit 1
fi

# Deal with the -d option independently since getopts does not handle
# options that may or may not have arguments
#
if [[ ${1} = "-d" ]] ; then
	if [[ $# -eq 1 ]] ; then	# remove the "default"
		${LPGET} -n system _default >/dev/null 2>&1
		exit_code=$?

		if [[ ${exit_code} -eq 0 ]] ; then
			${LPSET} -n system -x _default
			exit_code=$?
		else	# no default, nothing to do
			exit_code=0
		fi
	elif [[ $# -eq 2 ]] ; then	# add/change the "default"
		${LPGET} -k bsdaddr ${2} >/dev/null 2>&1
		exit_code=$?

		if [[ $exit_code -eq 0 ]] ; then
			${LPSET} -n system -a "use=${2}" _default
			exit_code=$?
		else	# can't set default to an unconfigured printer
			gettext "${2}: undefined printer\n" 1>&1
		fi
	else				# invalid usage
		usage
		exit 1
	fi

	exit ${exit_code}
fi

#		Strip off legal options
while getopts "A:ac:D:e:f:F:H:hi:I:lm:Mn:o:p:Q:r:S:s:T:u:U:v:W:x:t:P:" arg
do
	case $arg in
	D)
		description="${OPTARG}"
	;;
	n)
		ppd_file="${OPTARG}"
	;;
	p)
		if [[ -n "${delete}" ]] ; then
			usage
		fi
		printer=${OPTARG}
	;;
	s)
		server=${OPTARG}
	;;
	v|U)
		device=${OPTARG}
		if [[ ! -n "${server}" ]] ; then
			server=${HOST}
		fi
		local="true"
	;;
	x)
		if [[ -n "${printer}" || -n "${server}" || \
		     -n "${device}" || -n "${description}" ]] ; then
			usage
		fi
		delete=${OPTARG}
		printer=${OPTARG}
		if [[ ${printer} = "all" ]] ; then
			local="true"
		fi
	;;
	S|M|A)
		local="true"
	;;
	c)
		class=${OPTARG}
		local="true"
		if [[ ! -f ${LPGET} ]] ; then
			gettext "lpadmin: System error; cannot set class\n " 1>&2
			exit 2
		fi

		${LPGET} "${class}" > /dev/null 2>&1
		lpget_class=$?
		if [[ ${lpget_class} -eq 0 && ! -r /etc/lp/classes/"${class}" ]] ; then
			gettext "lpadmin: ERROR: Can't create class ${class}.\n" 1>&2
			gettext "           TO FIX: This is an existing printer name;\n" 1>&2
			gettext "                   choose another name.\n" 1>&2
			exit 1
		fi
	;;
	r)
		local="true"
	;;
	esac
done

#
# We don't have anything to do; let user know and bail
#
if [[ ! -n "${printer}" && ! -n "${delete}" && ! -n "${local}" ]] ; then
	gettext "lpadmin: ERROR: Nothing to do.\n" 1>&2
	gettext "        TO FIX: You must give one of these options:\n" 1>&2
	gettext "		      -p, -d, -x -S\n" 1>&2
	exit 1
fi

#
#       Printer does not exist
#       To be consistent with 2.5, assume adding local printer
#
if [[ ! -n "${device}" && ! -n "${server}" && ! -n "${delete}" && \
	  ! -n "${local}" ]] ; then
	${LPGET} "${printer}" > /dev/null 2>&1
	lpget_stat=$?
	if [[ ${lpget_stat} -ne 0 ]] ; then
		gettext "lpadmin: ERROR: Missing -U or -v option.\n" 1>&2
		gettext "           TO FIX: Local printers must have\n" 1>&2
		gettext "                   a port defined (-v option) or\n" 1>&2
		gettext "                   have dial-out instructions (-U option).\n" 1>&2
		exit 1
	fi
fi

#	process the "server" value
#	It can be a hostname, UUCP form (server!queue), RCMD form(queue@server),
#	or in URI form ({scheme}://{endpoint})
#		
case "${server}" in
	*://*)	# URI form
		uri=${server}
		rem_printer=$(expr "${server}" : ".*://.*/\([^/]*\)")
		server=$(expr "${server}" : ".*://\([^/]*\)/.*")
		;;
	*@*)	# RCMD form
		rem_printer=$(expr "${server}" : "\(.*\)@.*")
		server=$(expr "${server}" : ".*@\(.*\)")
		;;
	*!*)	# UUCP form
		rem_printer=$(expr "${server}" : ".*!\(.*\)")
		server=$(expr "${server}" : "\(.*\)!.*")
		;;
	*)	# hostname
		rem_printer=${printer}
		;;
esac

# if there is a "device" or LP configuration, it's local
if [[ -n "${device}" || -f /etc/lp/printers/${printer}/configuration || \
      -f /etc/lp/classes/${printer} ]] ; then
	local="true"
fi

# Do the LP configuration for a local printer served by lpsched
if [[ -x ${LPADMIN} && -n "${local}" ]] ; then
	# enumerate LP configured printers before modification
	PRE=$(${MKTEMP} lpadmin-pre.XXXXXX)
	if [[ -z "${PRE}" ]] ; then
		gettext "lpadmin: System error; cannot create temporary file\n" 1>&2
		exit 2
	fi

	(/bin/ls /etc/lp/printers 2>/dev/null ; /bin/ls /etc/lp/classes \
		2>/dev/null) >${PRE}

	# if there are no printers configured, enable LP service(s)
	[[ ! -s "${PRE}" ]] && lp_config_service enable

	# add filters to LP service
	lp_config_filters

	# add new ppd file to PPD file repositories
	if [[ -n "${ppd_file}" && -x ${PPDMGR} ]] ; then
		add_new_ppd_file "${ppd_file}"
	fi

	# modify LP destination(s)
	CMD="${PFEXEC} ${LPADMIN}"
	while [[ -n "$*" ]] ; do	# to deal with multi-word arguments
		CMD="$CMD \"$1\""
		# replace the ppd_file originally specified with the -n option
		# with the one returned from call to ppdmgr
		if [[ "${1}" = "-n" ]] ; then
			CMD="$CMD \"${ppd_file}\""
			shift
		fi
		shift
	done
	case "$CMD" in
		*\"-D\")
			CMD="$CMD \"\""
		;;
	esac

	# execute the LP lpadmin command
	eval $CMD
	exit_code=$?

	# enumerate LP configured printers after modification
	POST=$(${MKTEMP} lpadmin-post.XXXXXX)
	if [[ -z "${POST}" ]] ; then
		gettext "lpadmin: System error; cannot create temporary file\n" 1>&2
		/bin/rm -f ${PRE} >/dev/null 2>&1
		exit 2
	fi

	(/bin/ls /etc/lp/printers 2>/dev/null ; /bin/ls /etc/lp/classes \
		2>/dev/null) >${POST}

	# if there are no destinations, disable the service(s)
	[[ ! -s "${POST}" ]] && lp_config_service disable

	# sync printers.conf with LP configuration
	lp_config_sync_pconf "${PRE}" "${POST}"

	/bin/rm -f ${PRE} ${POST}
fi

# Do any printers.conf configuration that is required
if [[ -n "${delete}" ]] ; then
	if [[ "${delete}" = "all" ]] ; then
		[[ $exit_code -eq 0 ]] && delete_all
   	elif [[ -z "${local}" ]] ; then
   		${LPSET} -n system -x ${delete}
   		exit_code=$?
   	fi
else
	if [[ -z "${local}" ]] ; then
		# if we need a uri, find the "best" one.
		if [[ -z "${uri}" ]] ; then
			uri="ipp://${server}/printers/${rem_printer}"
			${LPSTAT} -p ${uri} >/dev/null 2>&1
			if [[ $? -ne 0 ]] ; then
				uri="lpd://${server}/printers/${rem_printer}#Solaris"
			fi
		fi
		# set the bsdaddr
		bsdaddr="${server},${rem_printer},Solaris"

		if [[ -n "${printer}" && -n "${server}" ]] ; then
			${LPSET} -n system \
				-a "printer-uri-supported=${uri}" \
				-a "bsdaddr=${bsdaddr}" ${printer}
			exit_code=$?
		fi

	fi

	if [[ -n "${printer}" && -n "${description}" ]] ; then
		${LPSET} -n system \
			-a "description=${description}" ${printer}
		exit_code=$?
	fi
fi

# if the "default" doesn't resolve a "bsdaddr", the printer is gone, remove it
${LPGET} -n system -k bsdaddr _default >/dev/null 2>&1 ||
	${LPSET} -n system -x _default >/dev/null 2>&1

exit $exit_code
